import Dep from "./observe/dep"
import { observe } from "./observe/index"
import Watcher from "./observe/watcher"

export function initState(vm) {
    const opts = vm.$options
    if (opts.data) {
        initData(vm)
    }
    if (opts.computed) {
        initComputed(vm)
    }
    if (opts.watch) {
        initWatch(vm)
    }
}

// 初始化watch
function initWatch(vm) {
    let watch = vm.$options.watch
    // console.log(watch)
    for (const key in watch) {
        const handler = watch[key]// 字符串，数组，函数
        if (Array.isArray(handler)) {
            for (let i = 0; i < handler.length; i++) {
                createWatcher(vm, key, handler[i])
            }
        }else{
            createWatcher(vm, key, handler)

        }
    }
}
function createWatcher(vm,key,handler) {
    // 字符串 函数
    if (typeof handler==='string') {
        handler=vm[handler]
    }
    return vm.$watch(key,handler)
}

function proxy(vm, target, key) {
    Object.defineProperty(vm, key, {
        get() {
            return vm[target][key]
        },
        set(newValue) {
            vm[target][key] = newValue
        }
    })
}

// 初始化data
function initData(vm) {
    let data = vm.$options.data
    data = typeof data === 'function' ? data.call(vm) : data
    vm._data = data
    // 对数据进行劫持 Object.defineProperty
    observe(data)
    // vm._data用vm代理
    for (let key in data) {
        proxy(vm, '_data', key)
    }
}

function initComputed(vm) {
    // debugger
    const computed = vm.$options.computed
    const watchers = vm._computedWatchers = {}//将计算属性watcher保存在vm上
    // console.log(computed)
    for (const key in computed) {//key='fullname'
        // debugger
        let userDef = computed[key]
        let fn = typeof userDef === 'function' ? userDef : userDef.get
        // console.log()
        // console.log(fn.call(vm),'fn')
        // debugger
        watchers[key] = new Watcher(vm, fn, { lazy: true })
        defineComputed(vm, key, userDef)
    }
}
function defineComputed(target, key, userDef) {
    // const getter = typeof userDef === 'function' ? userDef : userDef.get
    const setter = userDef.set || (() => { })
    // debugger
    //    console.log(getter,setter)
    Object.defineProperty(target, key, {
        get: createComputedGetter(key),
        set: setter
    })
}
// 计算属性根本不会收集依赖，只会让自己的依赖属性去收集依赖
function createComputedGetter(key) {
    return function () {
        const watcher = this._computedWatchers[key]//获取对应属性的watcher
        if (watcher.dirty) {// 求值后dirty就变成了false
            watcher.evaluate()
        }
        debugger
        if (Dep.target) {// 计算属性出栈后，还要渲染watcher，我应该让计算属性watcher里面的属性，也去收集上一层watcher
            watcher.depend()
        }
        return watcher.value//最后返回的是watcher上的值
    }
}